package com.zoe.onelink.core.util;


import com.zoe.onelink.core.util.http.HttpClient;
import com.zoe.onelink.core.util.http.HttpClientAsyncCallback;
import com.zoe.onelink.core.util.http.model.HttpClientEntity;
import com.zoe.onelink.core.util.http.model.HttpClientResponse;

import java.util.Map;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2021</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2021-10-18
 */
public class HttpClientUtil {

    /**
     * HttpClient 对象
     */
    private static HttpClient CLIENT;

    /**
     * 构造方法，用于初始化 HttpClientUtil 对象
     *
     * @param httpClient - 要初始化的 HttpClient 对象
     */
    public HttpClientUtil(HttpClient httpClient) {
        CLIENT = httpClient;
    }

    /**
     * 执行 HTTP 请求，并返回请求结果
     *
     * @param httpClientEntity - HTTP 请求的参数实体对象
     * @param resultType       - 请求结果类型的 Class 对象
     * @param <R>              - 请求结果类型
     * @return R - 请求结果对象
     */
    public static <R> R doRequest(HttpClientEntity httpClientEntity, Class<R> resultType) {
        return doRequestWithResp(httpClientEntity, resultType).getData();
    }

    /**
     * 执行 HTTP 请求，并返回请求结果的封装对象
     *
     * @param httpClientEntity - HTTP 请求的参数实体对象
     * @param resultType       - 请求结果类型的 Class 对象
     * @param <R>              - 请求结果类型
     * @return HttpClientResponse<R> - 请求结果的封装对象
     */
    public static <R> HttpClientResponse<R> doRequestWithResp(HttpClientEntity httpClientEntity, Class<R> resultType) {
        return CLIENT.doRequest(httpClientEntity, resultType);
    }

    /**
     * 异步执行 HTTP 请求，不关心请求结果
     *
     * @param httpClientEntity - HTTP 请求的参数实体对象
     */
    public static void doAsyncRequest(HttpClientEntity httpClientEntity) {
        doAsyncRequest(httpClientEntity, String.class, null);
    }

    /**
     * 异步执行 HTTP 请求，并在请求完成后执行回调
     *
     * @param httpClientEntity        - HTTP 请求的参数实体对象
     * @param returnType              - 请求结果类型的 Class 对象
     * @param httpClientAsyncCallback - 回调函数
     * @param <R>                     - 请求结果类型
     */
    public static <R> void doAsyncRequest(HttpClientEntity httpClientEntity, Class<R> returnType, HttpClientAsyncCallback<R> httpClientAsyncCallback) {
        CLIENT.doAsyncRequest(httpClientEntity, returnType, httpClientAsyncCallback);
    }

    /**
     * 发送 GET 请求，并返回请求结果的字符串形式
     *
     * @param url - 请求的 URL
     * @return String - 请求结果的字符串形式
     */
    public static String doGet(String url) {
        return doGet(url, null, String.class, 0, 0);
    }

    /**
     * 发送 GET 请求，并返回请求结果
     *
     * @param url        - 请求的 URL
     * @param returnType - 请求结果类型的 Class 对象
     * @param <R>        - 请求结果类型
     * @return R - 请求结果对象
     */
    public static <R> R doGet(String url, Class<R> returnType) {
        return doGet(url, null, returnType, 0, 0);
    }


    /**
     * 发送 GET 请求，并返回请求结果
     *
     * @param url        - 请求的 URL
     * @param returnType - 请求结果类型的 Class 对象
     * @param <R>        - 请求结果类型
     * @return R - 请求结果对象
     */
    public static <R> R doGet(String url, Map<String, String> urlParamMap, Class<R> returnType) {
        return doGet(url, urlParamMap, returnType, 0, 0);
    }

    /**
     * 发送 GET 请求，并返回请求结果
     *
     * @param url                  - 请求的 URL
     * @param returnType           - 请求结果类型的 Class 对象
     * @param connectTimeoutMillis 连接超时时间
     * @param callTimeoutMillis    请求超时时间
     * @param <R>                  - 请求结果类型
     * @return R - 请求结果对象
     */
    public static <R> R doGet(String url, Map<String, String> urlParamMap, Class<R> returnType, int connectTimeoutMillis, int callTimeoutMillis) {
        HttpClientEntity entity = HttpClientEntity.createGet(url, urlParamMap)
                .setConnectTimeoutMillis(connectTimeoutMillis)
                .setCallTimeoutMillis(callTimeoutMillis);
        return doRequest(entity, returnType);
    }

    /**
     * 发送 POST 请求，并返回请求结果
     *
     * @param url        - 请求的 URL
     * @param formMap    - 表单参数
     * @param returnType - 请求结果类型的 Class 对象
     * @param <T>        - 请求结果类型
     * @return T - 请求结果对象
     */
    public static <T> T doPost(String url, Map<String, String> formMap, Class<T> returnType) {
        return doPost(url, formMap, returnType, 0, 0);
    }

    /**
     * 发送 POST 请求，并返回请求结果
     *
     * @param url                  - 请求的 URL
     * @param formMap              - 表单参数
     * @param returnType           - 请求结果类型的 Class 对象
     * @param connectTimeoutMillis - 连接超时时间（单位：毫秒）
     * @param callTimeoutMillis    - 请求超时时间（单位：毫秒）
     * @param <T>                  - 请求结果类型
     * @return T - 请求结果对象
     */
    public static <T> T doPost(String url, Map<String, String> formMap, Class<T> returnType, int connectTimeoutMillis, int callTimeoutMillis) {
        HttpClientEntity httpClientEntity = HttpClientEntity.createPost(url, formMap)
                .setConnectTimeoutMillis(connectTimeoutMillis)
                .setCallTimeoutMillis(callTimeoutMillis);
        return doRequest(httpClientEntity, returnType);
    }

    /**
     * 发送 POST 请求，并返回请求结果
     *
     * @param url        - 请求的 URL
     * @param body       - 请求体参数
     * @param returnType - 请求结果类型的 Class 对象
     * @param <T>        - 请求结果类型
     * @return T - 请求结果对象
     */
    public static <T> T doPost(String url, String body, Class<T> returnType) {
        return doPost(url, body, returnType, 0, 0);
    }

    /**
     * 发送 POST 请求，并返回请求结果
     *
     * @param url                  - 请求的 URL
     * @param body                 - 请求体参数
     * @param returnType           - 请求结果类型的 Class 对象
     * @param connectTimeoutMillis - 连接超时时间（单位：毫秒）
     * @param callTimeoutMillis    - 请求超时时间（单位：毫秒）
     * @param <T>                  - 请求结果类型
     * @return T - 请求结果对象
     */
    public static <T> T doPost(String url, String body, Class<T> returnType, int connectTimeoutMillis, int callTimeoutMillis) {
        HttpClientEntity httpClientEntity = HttpClientEntity.createPost(url, body)
                .setConnectTimeoutMillis(connectTimeoutMillis)
                .setCallTimeoutMillis(callTimeoutMillis);
        return doRequest(httpClientEntity, returnType);
    }


}
